En este ejercicio, practicarƔs el anƔlisis de datos sobre un conjunto de datos abiertos procedentes de Airbnb. Algunas de las tareas incluyen:
Los criterios principales de la gente cuando visita lugares nuevos son contar con alojamiento y comida a precios razonables. Airbnb (Air-Bed-Breakfast) es un mercado en lĆnea creado para satisfacer esta necesidad, pues permite a la gente alquilar sus casas durante plazos cortos. Estos servicios se ofrecen a un precio relativamente inferior al de los hoteles y en diversas ubicaciones geogrĆ”ficas. AdemĆ”s, personas de todo el mundo prefieren el servicio hogareƱo y económico.
Puedes obtener el dataset para realizar este proyecto en el siguiente enlace: https://www.kaggle.com/datasets/arianazmoudeh/airbnbopendata
Este dataset contiene información sobre los alojamientos, tal como el barrio, el tipo de habitación, el precio, la disponibilidad, las opiniones, los gastos de servicio, la polĆtica de cancelación y las normas de uso de la casa.
”Te deseamos lo mejor en tu anÔlisis de los datos de Airbnb!
## Carga herramientas
# Sistemas
import sys
import os
# Manipulación
import pandas as pd
# MatemƔticas
import numpy as np
import statsmodels
# Visualización
import plotly.express as px
## Opciones
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
## Lee el fichero csv.
print(os.getcwd())
df_airbnb = pd.read_csv(os.path.normpath(os.path.join(os.getcwd(), 'Airbnb_Open_Data.csv')), header=0, sep=',', low_memory=False)
C:\Users\btoma\Downloads
## Muestra las primeras 5 filas.
print('\n\nNombres columnas:\n', df_airbnb.columns)
print('\n\nEstructura DataFrame:\n',df_airbnb.shape)
print('\n\nCinco primeras filas:\n', df_airbnb.head())
Nombres columnas:
Index(['id', 'NAME', 'host id', 'host_identity_verified', 'host name',
'neighbourhood group', 'neighbourhood', 'lat', 'long', 'country',
'country code', 'instant_bookable', 'cancellation_policy', 'room type',
'Construction year', 'price', 'service fee', 'minimum nights',
'number of reviews', 'last review', 'reviews per month',
'review rate number', 'calculated host listings count',
'availability 365', 'house_rules', 'license'],
dtype='object')
Estructura DataFrame:
(102599, 26)
Cinco primeras filas:
id NAME host id \
0 1001254 Clean & quiet apt home by the park 80014485718
1 1002102 Skylit Midtown Castle 52335172823
2 1002403 THE VILLAGE OF HARLEM....NEW YORK ! 78829239556
3 1002755 NaN 85098326012
4 1003689 Entire Apt: Spacious Studio/Loft by central park 92037596077
host_identity_verified host name neighbourhood group neighbourhood \
0 unconfirmed Madaline Brooklyn Kensington
1 verified Jenna Manhattan Midtown
2 NaN Elise Manhattan Harlem
3 unconfirmed Garry Brooklyn Clinton Hill
4 verified Lyndon Manhattan East Harlem
lat long country country code instant_bookable \
0 40.64749 -73.97237 United States US False
1 40.75362 -73.98377 United States US False
2 40.80902 -73.94190 United States US True
3 40.68514 -73.95976 United States US True
4 40.79851 -73.94399 United States US False
cancellation_policy room type Construction year price service fee \
0 strict Private room 2020.0 $966 $193
1 moderate Entire home/apt 2007.0 $142 $28
2 flexible Private room 2005.0 $620 $124
3 moderate Entire home/apt 2005.0 $368 $74
4 moderate Entire home/apt 2009.0 $204 $41
minimum nights number of reviews last review reviews per month \
0 10.0 9.0 10/19/2021 0.21
1 30.0 45.0 5/21/2022 0.38
2 3.0 0.0 NaN NaN
3 30.0 270.0 7/5/2019 4.64
4 10.0 9.0 11/19/2018 0.10
review rate number calculated host listings count availability 365 \
0 4.0 6.0 286.0
1 4.0 2.0 228.0
2 5.0 1.0 352.0
3 4.0 1.0 322.0
4 3.0 1.0 289.0
house_rules license
0 Clean up and treat the home the way you'd like... NaN
1 Pet friendly but please confirm with me if the... NaN
2 I encourage you to use my kitchen, cooking and... NaN
3 NaN NaN
4 Please no smoking in the house, porch or on th... NaN
## Muestra los tipos de datos.
print('\n\nTipo de dato por columna:\n', df_airbnb.dtypes)
Tipo de dato por columna: id int64 NAME object host id int64 host_identity_verified object host name object neighbourhood group object neighbourhood object lat float64 long float64 country object country code object instant_bookable object cancellation_policy object room type object Construction year float64 price object service fee object minimum nights float64 number of reviews float64 last review object reviews per month float64 review rate number float64 calculated host listings count float64 availability 365 float64 house_rules object license object dtype: object
host id, id, country y country code.Si utilizas Python para este ejercicio, incluye el código que hayas utilizado en las celdas siguientes. Si utilizas cualquier otra herramienta, incluye capturas de pantalla tomadas antes y después de eliminar las columnas.
## Elimina columnas no deseadas.
print("\n\nColumnas 'no deseadas':\n", df_airbnb[['host id', 'id', 'country', 'country code']].head())
df_airbnb = df_airbnb.drop(columns=['host id', 'id', 'country', 'country code']) # elimina
print("\n\nNombre columnas post-eliminación columnas 'no deseadas':\n", df_airbnb.columns)
### Las columnas host id, id, country, country code han sido elimandas porque no aportan
### información cuantitativa acerca de los alquileres
Columnas 'no deseadas':
host id id country country code
0 80014485718 1001254 United States US
1 52335172823 1002102 United States US
2 78829239556 1002403 United States US
3 85098326012 1002755 United States US
4 92037596077 1003689 United States US
Nombre columnas post-eliminación columnas 'no deseadas':
Index(['NAME', 'host_identity_verified', 'host name', 'neighbourhood group',
'neighbourhood', 'lat', 'long', 'instant_bookable',
'cancellation_policy', 'room type', 'Construction year', 'price',
'service fee', 'minimum nights', 'number of reviews', 'last review',
'reviews per month', 'review rate number',
'calculated host listings count', 'availability 365', 'house_rules',
'license'],
dtype='object')
## Comprueba si hay valores nulos y muestra el recuento en orden ascendente.
print('\n\nN total de NaN:\n', df_airbnb.isna().value_counts().sum()) # total valores nulos
print('\n\nN total de NaN por columna. Orden descendente:\n', df_airbnb.isna().sum().sort_values(ascending=False)) # total de valores nulos por columna de mayor a menor
# Elimina columnas no Ćŗtiles. Demasiados valores nulos
df_airbnb = df_airbnb.drop(columns=['license', 'house_rules', 'last review', 'reviews per month'])
print('\n\nN total de NaN por columna. Orden descendente:\n', df_airbnb.isna().sum().sort_values(ascending=False)) # comprueba de nuevo
# Elimina NaN del resto de columnas útiles. No son demasiado numerosos con relación al tamaño total del dataset
df_airbnb = df_airbnb.dropna()
print('\n\nSin valores nulos:\n', df_airbnb.isna().sum().sort_values(ascending=False)) # comprueba de nuevo
N total de NaN: 102599 N total de NaN por columna. Orden descendente: license 102597 house_rules 52131 last review 15893 reviews per month 15879 availability 365 448 minimum nights 409 host name 406 review rate number 326 calculated host listings count 319 host_identity_verified 289 service fee 273 NAME 250 price 247 Construction year 214 number of reviews 183 instant_bookable 105 cancellation_policy 76 neighbourhood group 29 neighbourhood 16 long 8 lat 8 room type 0 dtype: int64 N total de NaN por columna. Orden descendente: availability 365 448 minimum nights 409 host name 406 review rate number 326 calculated host listings count 319 host_identity_verified 289 service fee 273 NAME 250 price 247 Construction year 214 number of reviews 183 instant_bookable 105 cancellation_policy 76 neighbourhood group 29 neighbourhood 16 long 8 lat 8 room type 0 dtype: int64 Sin valores nulos: NAME 0 host_identity_verified 0 calculated host listings count 0 review rate number 0 number of reviews 0 minimum nights 0 service fee 0 price 0 Construction year 0 room type 0 cancellation_policy 0 instant_bookable 0 long 0 lat 0 neighbourhood 0 neighbourhood group 0 host name 0 availability 365 0 dtype: int64
## Comprueba si hay valores duplicados y elimĆnalos.
print('\n\nN total duplicados:\n', df_airbnb.duplicated().sum())
df_airbnb_clean = df_airbnb.drop_duplicates() # Crea nuevo DataFrame. LĆmpio de duplicados y de valores nulos
N total duplicados: 3565
## Muestra el número total de registros antes y después de eliminar los duplicados.
print('\n\nN total duplicados pre-limpieza:\n', df_airbnb.duplicated().sum())
print('\n\nN total duplicados post-limpieza:\n', df_airbnb_clean.duplicated().sum())
N total duplicados pre-limpieza: 3565 N total duplicados post-limpieza: 0
availability 365 a days_booked.price y service_fee. Si es necesario, convierte estas dos columnas al tipo de datos adecuado.Si utilizas Python para este ejercicio, incluye el código que hayas utilizado en las celdas siguientes. Si utilizas cualquier otra herramienta, incluye capturas de pantalla de tu trabajo.
## Cambia el nombre de la columna.
df_airbnb_clean = df_airbnb_clean.rename(columns={'availability 365': 'days_booked'})
## Convierte todos los nombres de columna a minúsculas y sustituye los espacios por un guión bajo "_".
df_airbnb_clean.columns = (df_airbnb_clean.columns.str.lower()) # cambia todos los nombres de las columnas a minĆŗscula
df_airbnb_clean.columns = [i.replace(' ', '_') for i in df_airbnb_clean.columns] # reemplaza toda substring ' ' por '_', dentro de los nombres de las columnas
print(df_airbnb_clean.columns)
Index(['name', 'host_identity_verified', 'host_name', 'neighbourhood_group',
'neighbourhood', 'lat', 'long', 'instant_bookable',
'cancellation_policy', 'room_type', 'construction_year', 'price',
'service_fee', 'minimum_nights', 'number_of_reviews',
'review_rate_number', 'calculated_host_listings_count', 'days_booked'],
dtype='object')
## Elimina el signo de dólares y la coma de las columnas. Si es necesario, convierte estas dos columnas al tipo de datos adecuado.
print(df_airbnb_clean[['price', 'service_fee']].head())
df_airbnb_clean['price'] = pd.to_numeric(df_airbnb_clean['price'].str.replace('$', ''), downcast='integer', errors='coerce')
df_airbnb_clean['service_fee'] = pd.to_numeric(df_airbnb_clean['service_fee'].str.replace('$', ''), downcast='integer', errors='coerce')
print(df_airbnb_clean[['price', 'service_fee']].head())
print(df_airbnb_clean[['price', 'service_fee']].dtypes)
price service_fee 0 $966 $193 1 $142 $28 4 $204 $41 5 $577 $115 7 $1,060 $212 price service_fee 0 966.0 193 1 142.0 28 4 204.0 41 5 577.0 115 7 NaN 212 price float64 service_fee int16 dtype: object
Si utilizas Python para este ejercicio, incluye el código que hayas utilizado en las celdas siguientes. Si utilizas cualquier otra herramienta, incluye capturas de pantalla de tu trabajo.
## Enumera los tipos de habitaciones disponibles en Airbnb.
print(df_airbnb_clean['room_type'].nunique()) # nĆŗmero de categorĆas
print(df_airbnb_clean['room_type'].unique()) # categorĆas
4 ['Private room' 'Entire home/apt' 'Shared room' 'Hotel room']
## ĀæQuĆ© tipo de habitación se adhiere a una polĆtica de cancelación mĆ”s estricta?
print(df_airbnb_clean.groupby('room_type')['cancellation_policy'].first()) # 'Private room'
room_type Entire home/apt moderate Hotel room flexible Private room strict Shared room flexible Name: cancellation_policy, dtype: object
## Enumera los precios por barrio y menciona tambiƩn cuƔl es el grupo de barrios con alquileres mƔs caros.
print(df_airbnb_clean['neighbourhood_group'].unique()) # errata en los valores Ćŗnicos dentro de 'neighbourhood_group' ('brookln')
# Corrige errata
df_airbnb_clean['neighbourhood_group'] = df_airbnb_clean['neighbourhood_group'].replace('brookln', 'Brooklyn')
print(df_airbnb_clean['neighbourhood_group'].unique()) # correción ok
print('\n\nAlquileres medios por grupo de barrios:\n', df_airbnb_clean.groupby('neighbourhood_group')['price'].mean().sort_values(ascending=False)) # en promedio 'Bronx' es el grupo de barrios con alquileres mƔs caros
print('\n\nAlquileres medios por barrio:\n', df_airbnb_clean.groupby('neighbourhood')['price'].mean().sort_values(ascending=False).head(10)) # barrios por precio promedio
['Brooklyn' 'Manhattan' 'brookln' 'Queens' 'Bronx' 'Staten Island'] ['Brooklyn' 'Manhattan' 'Queens' 'Bronx' 'Staten Island'] Alquileres medios por grupo de barrios: neighbourhood_group Bronx 534.633810 Staten Island 533.962315 Brooklyn 525.089970 Queens 523.866024 Manhattan 523.692022 Name: price, dtype: float64 Alquileres medios por barrio: neighbourhood Shore Acres 762.117647 Arden Heights 710.285714 Gerritsen Beach 694.333333 Little Neck 691.666667 Huguenot 691.111111 Eltingville 690.333333 Dongan Hills 663.454545 Graniteville 658.333333 Olinville 648.100000 Kew Gardens Hills 638.542373 Name: price, dtype: float64
Si utiliza Python para este ejercicio, por favor incluya el código en las celdas de abajo. Si utiliza cualquier otra herramienta, por favor incluya pantallazos de su trabajo.
## Bar plot horizontal. Top 10 barrios mƔs caros. Orden ascendente
# Selecciona top 10 barrios mƔs caros en precio promedio
df_top10_expensive_neighbourhoods = df_airbnb_clean.groupby('neighbourhood')['price'].mean().sort_values(ascending=False).head(10)
# Re-ordena por de menor a mayor
df_top10_expensive_neighbourhoods = df_top10_expensive_neighbourhoods.sort_values(ascending=True)
# Crea bar plot
fig_top10_expensive_neighbourhoods = px.bar(data_frame = df_top10_expensive_neighbourhoods,
orientation = 'h')
# Actualiza 'traces'
fig_top10_expensive_neighbourhoods.update_traces(name='Precios ($)')
# Actualiza tĆtulos eje 'x' y eje 'y'
fig_top10_expensive_neighbourhoods.update_xaxes(title_text='Precios promedio')
fig_top10_expensive_neighbourhoods.update_yaxes(title_text='Barrio')
# Actualiza estilo figura para visualización mÔs agradable
fig_top10_expensive_neighbourhoods.update_layout(title='<b>ALQUILERES AIRBNB NUEVA YORK. TOP 10 BARRIOS MĆS CAROS<b>',
plot_bgcolor='white', # fondo blanco
legend_title_text='Legenda', # cambia tĆtulo de la leyenda a espaƱol
xaxis=dict(showgrid=True, # muestra lĆneas verticales
gridcolor='lightgrey', # color gris claro
gridwidth=1)) # grosor lĆnea
# Muestra bar plot
fig_top10_expensive_neighbourhoods.show()
## Bar plot vertical. Barrios con mayor nĆŗmero de alquileres de corta duración (menos de 10 dĆas)
# Filtra barrios con estancias de 10 noches o menos. Total de observaciones por barrio. Ordenados de mayor a menor
df_shortstay_neighbourhoods = df_airbnb_clean[df_airbnb_clean['minimum_nights'] <= 10] \
.groupby('neighbourhood')['minimum_nights'] \
.size() \
.sort_values(ascending=False) # el método .size() contabiliza el número total de observaciones dentro de cada grupo
# Crea bar plot
plot_shortstay_neighbourhoods = px.bar(data_frame = df_shortstay_neighbourhoods,
orientation = 'v')
# Actualiza 'traces'
plot_shortstay_neighbourhoods.update_traces(name='Estancias cortas (menos de 10 noches)')
# Actualiza tĆtulos eje 'x' y eje 'y'
plot_shortstay_neighbourhoods.update_xaxes(title_text='Barrio')
plot_shortstay_neighbourhoods.update_yaxes(title_text='Total estancias corta duración')
# Actualiza estilo figura para visualización mÔs agradable
plot_shortstay_neighbourhoods.update_layout(title='<b>ALQUILERES AIRBNB NUEVA YORK. BARRIOS CON MĆS ESTANCIAS DE CORTA DURACIĆN<b>',
plot_bgcolor='white', # fondo blanco
legend_title_text='Legenda', # cambia tĆtulo de la leyenda a espaƱol
yaxis=dict(showgrid=True, # muestra lĆneas horizontales
gridcolor='lightgrey', # color gris claro
gridwidth=1)) # grosor lĆnea
# Muestra bar plot
plot_shortstay_neighbourhoods.show()
## Bar plot. Precios del alquiler por tipo de habitación. Indica inferencias con anÔlisis formal
# Agrupa tipo de habitación por precio. Ordenados de mayor a menor
df_neighbourhoods_room_type = df_airbnb_clean.groupby('room_type')['price'].mean().sort_values(ascending=False)
# Crea bar plot
plot_neighbourhoods_room_type = px.bar(data_frame = df_neighbourhoods_room_type,
orientation = 'v')
# Actualiza 'traces'
plot_neighbourhoods_room_type.update_traces(name='Precios ($)')
# Actualiza tĆtulos eje 'x' y eje 'y'
plot_neighbourhoods_room_type.update_xaxes(title_text='Tipo de habitación')
plot_neighbourhoods_room_type.update_yaxes(title_text='Precio promedio')
# Actualiza estilo figura para visualización mÔs agradable
plot_neighbourhoods_room_type.update_layout(title='<b>ALQUILERES AIRBNB NUEVA YORK. PRECIOS PROMEDIO POR TIPO DE HABITACIĆN<b>',
plot_bgcolor='white', # fondo blanco
legend_title_text='Legenda', # cambia tĆtulo de la leyenda a espaƱol
yaxis=dict(showgrid=True, # muestra lĆneas horizontales
gridcolor='lightgrey', # color gris claro
gridwidth=1)) # grosor lĆnea
# Muestra bar plot
plot_neighbourhoods_room_type.show()
## Pie chart. Distribución de dĆas reservados por grupo de barrios
df_bookings_neighbourhood_group = df_airbnb_clean.groupby('neighbourhood_group')['days_booked'].sum().sort_values(ascending=False)
# Crea pie chart
fig_pie_bookings_ngroup = px.pie(df_bookings_neighbourhood_group.reset_index(),
values='days_booked',
names='neighbourhood_group',
title='<b>ALQUILERES AIRBNB NUEVA YORK. DISTRIBUCIĆN DEL VOLUMEN DE DĆAS RESERVADOS SEGĆN BARRIO<b>')
# Muestra pie chart
fig_pie_bookings_ngroup.show()
Si utiliza Python para este ejercicio, incluya el código en las celdas siguientes. Si utiliza cualquier otra herramienta, incluya capturas de pantalla de su trabajo.
# Scatter plot. Precio servicio vs precio habitación
# Selecciona sólo columnas 'service_fee' y 'price'. Asegura que no haya NaN
df_servicefee_price = df_airbnb_clean[['service_fee', 'price']].dropna()
fig_scatter_service_fee_price = px.scatter(df_servicefee_price,
x='service_fee',
y='price',
trendline='ols', # dibuja 'ols' ('Ordinary Least Squares'). LĆnea de regresión calculada en base al mĆ©todo 'Least Squares' ó 'MĆnimos cuadrados'
trendline_color_override = 'red', # color 'ols'
title='<b>ALQUILERES AIRBNB NUEVA YORK. RELACIĆN TARIFA SERVICIO VS PRECIO<b>')
# Actualiza tĆtulos eje 'x' y eje 'y'
fig_scatter_service_fee_price.update_xaxes(title_text='Tarifa servicio')
fig_scatter_service_fee_price.update_yaxes(title_text='Precio')
# Actualiza estilo figura
fig_scatter_service_fee_price.update_layout(plot_bgcolor='white', # fondo blanco
yaxis=dict(showgrid=True, # muestra lĆneas horizontales
gridcolor='lightgrey', # color gris claro
gridwidth=1)) # grosor lĆnea
# Muestra scatter plot
fig_scatter_service_fee_price.show()
# Concusiones
print("A nivel visual, parece haber una clara relación directa entre 'precio' y 'tarifa de servicio'")
print("\n\nDe hecho, el coeficiente de correlación entre ambas variables es de 0.99:'\n", (df_airbnb_clean[['service_fee', 'price']].dropna()).corr(method='pearson'))
A nivel visual, parece haber una clara relación directa entre 'precio' y 'tarifa de servicio'
De hecho, el coeficiente de correlación entre ambas variables es de 0.99:'
service_fee price
service_fee 1.000000 0.999987
price 0.999987 1.000000
# Line plot. Construcción de habitaciones a lo largo del tiempo
df_rooms_built_per_year = df_airbnb_clean.groupby('construction_year').size()
# Crea line plot
fig_line_plot = px.line(df_rooms_built_per_year, title='<b>ALQUILERES AIRBNB NUEVA YORK. HABITACIONES CONSTRUIDAS POR AĆO<b>')
# Actualiza tĆtulos eje 'x' y eje 'y'
fig_line_plot.update_xaxes(title_text='Año construcción')
fig_line_plot.update_yaxes(title_text='NĆŗmero habitaciones')
# Esconde leyenda
fig_line_plot.update_layout(showlegend=False,
plot_bgcolor='white',
yaxis=dict(showgrid=True, # muestra lĆneas horizontales
gridcolor='lightgrey', # color gris claro
gridwidth=1)) # grosor lĆnea
# Muestra line plot
fig_line_plot.show()
print('2014 fue el año con mayor número de habitaciones construidas con 4901')
2014 fue el año con mayor número de habitaciones construidas con 4901
Si utiliza Python para este ejercicio, por favor incluya el código en las celdas de abajo. Si utiliza cualquier otra herramienta, por favor incluya capturas de pantalla de su trabajo.
## Box plot. Impacto del número de tasa de revisión en el precio
# Crea box plot
box_review_rate = px.box(df_airbnb_clean,
x='review_rate_number',
y='price',
color='review_rate_number',
title='<b>ALQUILERES AIRBNB NUEVA YORK. BOX PLOTS IMPACTO DEL NĆMERO MEDIO DE RESEĆAS EN EL PRECIO<b>')
# Actualiza tĆtulos eje 'x' y eje 'y'
box_review_rate.update_xaxes(title_text='Número de tasa de reseñas')
box_review_rate.update_yaxes(title_text='Precio')
# Muestra box plot
box_review_rate.show()
# Conclusión
print('A nivel visual, no parece haber gran diferencia en el precio de las habitaciones, segĆŗn la tasa de reviews de los clientes')
A nivel visual, no parece haber gran diferencia en el precio de las habitaciones, segĆŗn la tasa de reviews de los clientes
## Box plot. Impacto de id host verificada en el precio
# Crea box plot
box_review_rate = px.box(df_airbnb_clean,
x='host_identity_verified',
y='price',
color='host_identity_verified',
title='<b>ALQUILERES AIRBNB NUEVA YORK. BOX PLOTS IMPACTO DE LA CONFIRMACIĆN DE IDENTIDAD DEL PROPIETARIO EN EL PRECIO<b>')
# Actualiza tĆtulos eje 'x' y eje 'y'
box_review_rate.update_xaxes(title_text='Identidad del host: no confirmada / confirmada')
box_review_rate.update_yaxes(title_text='Precio')
# Muestra box plot
box_review_rate.show()
# Conclusión
print('A nivel visual, no parece haber una diferencia significativa, entre los precios de aquellas habitaciones que aportan confirmación de la identidad del propietario y los precios de aquellas habitaciones que no aportan confirmación de identidad del propietario')
A nivel visual, no parece haber una diferencia significativa, entre los precios de aquellas habitaciones que aportan confirmación de la identidad del propietario y los precios de aquellas habitaciones que no aportan confirmación de identidad del propietario